/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-10
 * V4.0
 */
package com.jphenix.clazz;

import com.jphenix.standard.docs.ClassInfo;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * <code>field_info</code> structure.
 *
 * @author mabg
 * @see //javassist.CtField#getFieldInfo()
 */
@ClassInfo({"2014-06-10 19:59","FieldInfo"})
public final class FieldInfo {
    
    ConstPool constPool;
    int accessFlags;
    int name;
    String cachedName;
    String cachedType;
    int descriptor;
    ArrayList<AttributeInfo> attribute;       // may be null.

    private FieldInfo(ConstPool cp) {
        constPool = cp;
        accessFlags = 0;
        attribute = null;
    }

    /**
     * Constructs a <code>field_info</code> structure.
     *
     * @param cp                a constant pool table
     * @param fieldName         field name
     * @param desc              field descriptor
     *
     * @see Descriptor
     */
    public FieldInfo(ConstPool cp, String fieldName, String desc) {
        this(cp);
        name = cp.addUtf8Info(fieldName);
        cachedName = fieldName;
        descriptor = cp.addUtf8Info(desc);
    }

    public FieldInfo(ConstPool cp, DataInputStream in) throws IOException {
        this(cp);
        read(in);
    }

    /**
     * Returns a string representation of the object.
     */
    @Override
    public String toString() {
        return getName() + " " + getDescriptor();
    }

    /**
     * Returns the constant pool table used
     * by this <code>field_info</code>.
     */
    public ConstPool getConstPool() {
        return constPool;
    }

    /**
     * Returns the field name.
     */
    public String getName() {
       if (cachedName == null) {
           cachedName = constPool.getUtf8Info(name);
       }

       return cachedName;
    }


    /**
     * Returns the access flags.
     *
     * @see AccessFlag
     */
    public int getAccessFlags() {
        return accessFlags;
    }

    /**
     * Returns the field descriptor.
     *
     * @see Descriptor
     */
    public String getDescriptor() {
        return constPool.getUtf8Info(descriptor);
    }

    /**
     * Finds a ConstantValue attribute and returns the index into
     * the <code>constant_pool</code> table.
     *
     * @return 0    if a ConstantValue attribute is not found.
     */
    public int getConstantValue() {
        if ((accessFlags & AccessFlag.STATIC) == 0) {
            return 0;
        }

        ConstantAttribute attr
            = (ConstantAttribute)getAttribute(ConstantAttribute.tag);
        if (attr == null) {
            return 0;
        } else {
            return attr.getConstantValue();
        }
    }

    /**
     * Returns all the attributes.    The returned <code>List</code> object
     * is shared with this object.  If you add a new attribute to the list,
     * the attribute is also added to the field represented by this
     * object.  If you remove an attribute from the list, it is also removed
     * from the field.
     *
     * @return a list of <code>AttributeInfo</code> objects.
     * @see AttributeInfo
     */
    public List<AttributeInfo> getAttributes() {
        if (attribute == null) {
            attribute = new ArrayList<AttributeInfo>();
        }

        return attribute;
    }

    /**
     * Returns the attribute with the specified name.
     * It returns null if the specified attribute is not found.
     *
     * @param name      attribute name
     * @see #getAttributes()
     */
    public AttributeInfo getAttribute(String name) {
        return AttributeInfo.lookup(attribute, name);
    }


    private void read(DataInputStream in) throws IOException {
        accessFlags = in.readUnsignedShort();
        name = in.readUnsignedShort();
        descriptor = in.readUnsignedShort();
        int n = in.readUnsignedShort();
        attribute = new ArrayList<AttributeInfo>();
        for (int i = 0; i < n; ++i) {
            attribute.add(AttributeInfo.read(constPool, in));
        }
    }
}
